package com.hxgis.common.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hxgis.common.vo.GeoJsonVO;
import lombok.extern.slf4j.Slf4j;
import org.geojson.Feature;
import org.geojson.FeatureCollection;
import org.geojson.LngLatAlt;
import org.geojson.Polygon;
import wContour.Contour;
import wContour.Global.Border;
import wContour.Global.PointD;
import wContour.Global.PolyLine;
import wContour.Interpolate;

import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author BLQ
 * @date 2019/6/24 13:57
 */
@Slf4j
public class GeoJsonUtil {


    public static String getBound(String areaType, String rootPath) {
        String bourds = "";
        String jsonFileName = "";
        if (areaType.equals("海河流域")) {
//            jsonFileName = "hb_province_boundary.json";
            jsonFileName = "海河流域.json";
        }else {
            jsonFileName = areaType + ".json";
        }

        StringBuilder builder = new StringBuilder();
        // 读取对应的json边界文件
        String filePath = rootPath + "/" + jsonFileName;
//        StringBuffer buffer = FileUtils.BufferReaderFile(filePath, "utf-8");
        StringBuffer buffer = null;//jar 包读取文件
        try {
            buffer = ConfigJson.getStringBuffer(filePath, "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        }

        JSONObject jsonObj = (JSONObject) JSONObject.parse(buffer.toString());
        JSONArray jsonArray = jsonObj.getJSONArray("features");
        if (jsonArray.size() > 0) {
            JSONObject boundObj = jsonArray.getJSONObject(0);
            JSONObject geometryObj = boundObj.getJSONObject("geometry");
            JSONArray coorArray = geometryObj.getJSONArray("coordinates");
            int size = coorArray.size();
            if (coorArray.size() > 0) {
                for (int i = 0; i < size; i++) {
                    JSONArray pointArray = coorArray.getJSONArray(i);
                    int count = pointArray.size();
                    if(count>0){
                        Object testPoint = pointArray.get(0);
                        if(testPoint instanceof JSONArray){
                            for (int j = 0; j < count; j++) {
                                JSONArray point = pointArray.getJSONArray(j);
                                builder.append(point.getString(0) + "," + point.getString(1) + ";");
                            }
                        } else if (testPoint instanceof BigDecimal){
                            builder.append(((BigDecimal)testPoint).toString() + "," + ((BigDecimal)(pointArray.get(1))).toString() + ";");
                        }
                    }
                }
            }
        }

        bourds = builder.toString();
        if (bourds.length() > 0) {
            bourds = bourds.substring(0, bourds.length() - 1);
        }

        return bourds;
    }

    /**
     * 站点数据生成色斑图GeoJson
     * @param contourValues 色卡值
     * @param contourColors 色卡颜色 颜色要比色卡值多写一个
     * @param removeColor 忽略颜色 无传空字符串
     * @param lonRes 经度分辨率
     * @param latRes 纬度分辨率
     * @param lonMin 最小经度
     * @param lonMax 最大经度
     * @param latMin 最小纬度
     * @param latMax 最大纬度
     * @param clipLons 裁剪边界经度 不裁剪 传null
     * @param clipLats 裁剪边界纬度 不裁剪 传null
     * @param lons 站点经度
     * @param lats 站点纬度
     * @param vals 站点值
     * @param unDefData 无效值
     * @param unit 图列单位
     * @return
     */
    public static String staDatatoGeoJson(double[] contourValues, String[] contourColors, String removeColor, double lonRes, double latRes
            , double lonMin, double lonMax, double latMin, double latMax,double[] clipLons,double[] clipLats, double[] lons, double[] lats, double vals[], double unDefData, String unit,String filePath) {

        //构建空格点
        int xNum = (int) ((lonMax - lonMin) / lonRes);
        int yNum = (int) ((latMax - latMin) / latRes);
        double[] gridX = new double[xNum];
        double[] gridY = new double[yNum];
        for (int i = 0; i < xNum; i++) {
            gridX[i] = lonMin + i * lonRes;
        }
        for (int i = 0; i < yNum; i++) {
            gridY[i] = latMin + i * latRes;
        }

        //站点数据
        double[][] staData = new double[vals.length][3];
        double[][] grid = null;
        for (int i = 0; i < staData.length; i++) {
            staData[i][0] = lons[i];
            staData[i][1] = lats[i];
            staData[i][2] = vals[i];
        }
        Interpolate.createGridXY_Num(lonMin, latMin, lonMax, latMax, gridX,
                gridY);

        //插值
        long startTime = System.currentTimeMillis();
        grid = Interpolate.interpolation_IDW_Neighbor(staData, gridX, gridY, 3, unDefData);
//        grid = Interpolate.interpolation_IDW_Radius(staData, gridX, gridY, 1, 3, unDefData);
        log.info("插值用时:,{}",(System.currentTimeMillis() - startTime));
        String json = GeoJsonUtil.gridtoGeoJsonStr(xNum, yNum, gridX, gridY, grid,clipLons,clipLats, contourValues, contourColors, removeColor, unDefData ,unit,filePath);
        return json;
    }


    public static String gridtoGeoJsonStr(int xNum, int yNum, double[] xs, double[] ys, double[][] grid,double[] clipLons,double[] clipLats
            , double[] contourValues, String[] contourColors, String removeColor, double undefData, String unit, String filePath) {
        int[][] S1 = new int[yNum][xNum];

        List<Border> borders = Contour.tracingBorders(grid, xs, ys, S1, undefData);

        //初始版本
        long startTime = System.currentTimeMillis();
        int nc = contourValues.length;
        List<PolyLine> contourLines = Contour.tracingContourLines(grid, xs, ys, nc,
                contourValues, undefData, borders, S1);
        log.info("tracingContourLines:,{}" ,(System.currentTimeMillis() - startTime));
        contourLines = Contour.smoothLines(contourLines);
        log.info("smoothLines:,{}" , (System.currentTimeMillis() - startTime));
        List<wContour.Global.Polygon> contourPolygons = Contour.tracingPolygons(grid, contourLines,
                borders, contourValues);
        log.info("tracingPolygons:,{}",(System.currentTimeMillis() - startTime));


        //裁剪
//        String filePath = "public/国界.txt";
//        List<String> boundStr = FileUtil.readFile(filePath);

        List<wContour.Global.Polygon> clippedPolys = new ArrayList<>();
//        for (int i = 0; i < boundStr.size(); i++) {
//            String[] boundPointArray = boundStr.get(i).split(";");
//            int pointSize = boundPointArray.length;
//            List<PointD> clipPs = new ArrayList<>();
//            for (int j = 0; j < pointSize; j ++) {
//                String[] point = boundPointArray[j].split(",");
//                clipPs.add(new PointD(Double.parseDouble(point[0]),Double.parseDouble(point[1])));
//            }
//            clippedPolys.addAll(Contour.clipPolygons(contourPolygons,clipPs));
//        }
//        log.info("裁剪用时:,{}",(System.currentTimeMillis() - startTime));


        FeatureCollection features = new FeatureCollection();
//        for (int i = 0; i < clippedPolys.size(); i++) {
        for (int i = 0; i < contourPolygons.size(); i++) {
            Polygon polygon = new Polygon();
            wContour.Global.Polygon cpoly = contourPolygons.get(i);
            polygon.setExteriorRing(getGeoJsonPoints(cpoly.OutLine.PointList));
            if (cpoly.HasHoles()) {
                for (int j = 0; j < cpoly.HoleLines.size(); j++) {
                    PolyLine hole = cpoly.HoleLines.get(j);
                    polygon.addInteriorRing(getGeoJsonPoints(hole.PointList));
                }
            }

            Feature feature = new Feature();
            feature.setGeometry(polygon);

            Map<String, Object> prop = new HashMap<>();
            prop.put("isHighCenter", cpoly.IsHighCenter);
            prop.put("lowValue", cpoly.LowValue);
            prop.put("highValue", cpoly.HighValue);
            String color = getFillColor(cpoly, contourValues, contourColors);
            if (color.equals(removeColor)) {
                continue;
            }
            prop.put("color", color);
//            prop.put("unit", unit);
            feature.setProperties(prop);
            features.add(feature);
        }

//        Feature feature = new Feature();
//        Map<String, Object> prop = new HashMap<>();
//        prop.put("contourValues", contourValues);
//        prop.put("contourColors", contourColors);
//        prop.put("unit", unit);
//        feature.setProperties(prop);
//
//        features.add(feature);
        GeoJsonVO geoJsonVO = new GeoJsonVO();
        geoJsonVO.setFeatures(features);
        geoJsonVO.setUnit(unit);
        geoJsonVO.setColorCard(contourColors);
        geoJsonVO.setContourValues(contourValues);
        String json = "";
        try {
            json = new ObjectMapper().writeValueAsString(geoJsonVO);
        } catch (Exception ex) {
            //todo
        }
        return json;
    }

    private static String getFillColor(wContour.Global.Polygon poly, double[] contourValues, String[] contourColors) {
        if (poly.LowValue != poly.HighValue) {
            return contourColors[getIndex(poly.HighValue, contourValues)];  //带镂空的
        } else {
            if (poly.IsHighCenter) {
                return contourColors[getIndex(poly.HighValue, contourValues) + 1];  //不带镂空中心递增
            } else {
                return contourColors[getIndex(poly.HighValue, contourValues)]; //不带镂空中心递减
            }
        }
    }

    private static int getIndex(double val, double[] values) {
        for (int i = 0; i < values.length; i++) {
            if (val == values[i])
                return i;
        }
        return -1;
    }

    private static List<LngLatAlt> getGeoJsonPoints(List<PointD> pointDs) {
        List<LngLatAlt> points = new ArrayList<>();
        for (int i = 0; i < pointDs.size(); i++) {
            PointD pd = pointDs.get(i);
            points.add(new LngLatAlt(pd.X, pd.Y, 0));
        }
        return points;
    }

    private static double setScale(double value, int scale) {
        BigDecimal bg = new BigDecimal(value);
        return bg.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }



}
